package controller;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import entity.DecisionLinesEvent;
import entity.Edge;

import server.ClientData;
import server.ClientState;
import server.IProtocolHandler;
import server.Server;
import server.ServerThread;
import xml.Message;

public class AddEdgeController implements IProtocolHandler {

	@Override
	public Message process(ClientState state, Message request) {
		entity.System system = entity.System.getInstance();
		
		Node addEdgeRequest = request.contents.getFirstChild();
		NamedNodeMap map = addEdgeRequest.getAttributes();
		String eventId = map.getNamedItem("id").getNodeValue();
		int left   = Integer.valueOf(map.getNamedItem("left").getNodeValue());
		int right  = Integer.valueOf(map.getNamedItem("right").getNodeValue());
		int height = Integer.valueOf(map.getNamedItem("height").getNodeValue());
		
		
		DecisionLinesEvent event = system.getEvent(eventId);
		Edge e = new Edge(left,height,right);
		event.addEdge(e);
		system.updateEvent(eventId, event);
		
		//TODO Shouldn't we check to make sure that the edge is actually valid (i.e. doesn't conflict
		// with any other edges)?
		
		// addEdgeResponse to be broadcast
		NamedNodeMap requestMap = request.contents.getAttributes();
		String response = Message.responseHeader(requestMap.getNamedItem("id").getNodeValue());
		response += "<addEdgeResponse id='"+eventId+"' left='"+left+"' right='"+right+"' height='"+height+"' /></response>";
		Message addEdgeResponse = new Message(response);
		
		// The message to be returned to the current client
		Message returnedMessage;
		
		// Broadcast the appropriate messages and determine which message should be returned,
		// based on whether the event is done as a result of adding the edge.
		if (event.isDone()) {
			event.setPhase("completed");
			system.updateEvent(eventId, event);
			
			// Broadcast the appropriate addEdgeResponse to everyone
			ServerThread.broadcastMessage(addEdgeResponse, eventId, null);
			
			// Broadcast a turnResponse to everyone except the current client and
			// save it as the returned message
			response = Message.responseHeader(requestMap.getNamedItem("id").getNodeValue())
					+ "<turnResponse completed='true' /></response>";
			returnedMessage = new Message(response);
			ServerThread.broadcastMessage(returnedMessage, eventId, state.id());
		} else {
			// Otherwise broadcast the addEdgeResponse to everyone except the current
			// client and save it as the returned message
			system.updateEvent(eventId, event);
			ServerThread.broadcastMessage(addEdgeResponse, eventId, state.id());
			returnedMessage = addEdgeResponse;
			
			response = Message.responseHeader(requestMap.getNamedItem("id").getNodeValue())
					+ "<turnResponse completed='false'/></response>";
			if(event.getTurnType().equals("roundRobin")){
				int i;
				for(i = 0;i<event.getUsers().size();i++){
					if(event.getUsers().get(i).getUserName().equals(event.getTurn())){
						// found who's turn it was
						break;
					}
				}
				
				i = (i+1) % event.getUsers().size();
				event.setTurn(event.getUsers().get(i).getUserName());
				system.updateEvent(eventId, event);
				
				// Now we gotta find his connection
				for(String id : Server.ids()){
					if(((ClientData)Server.getState(id).getData()).getUsername().equals(event.getTurn())){
						Server.getState(id).sendMessage(new Message(response));
						break;
					}
				}
			}
		}
		
		return returnedMessage;
	}

}


/* Relevant schema
<xs:element name='addEdgeRequest'> 
  <xs:complexType>
    <xs:attribute name='id'         type='xs:string' use='required'/>
    <xs:attribute name='left'       type='xs:int' use='required'/>
    <xs:attribute name='right'      type='xs:int' use='required'/>
    <xs:attribute name='height'     type='xs:int' use='required'/>
  </xs:complexType>
</xs:element>

<xs:element name='addEdgeResponse'>
  <xs:complexType>
    <xs:attribute name='id'         type='xs:string' use='required'/>
    <xs:attribute name='left'       type='xs:int' use='required'/>
    <xs:attribute name='right'      type='xs:int' use='required'/>
    <xs:attribute name='height'     type='xs:int' use='required'/>
  </xs:complexType>
</xs:element>
*/